import React from 'react'
import {Tree, Input, Menu} from 'antd'
import {
    cloneDeep,
    findIndex,
    forEach,
    forIn,
    indexOf,
    isArray,
    isEmpty,
    isFunction,
    isString,
    keys,
    omit
} from 'lodash-es'
import BaseComp from "../Base/BaseComp";
import PropTypes from "prop-types";
import {getRandomKey, isObjectValEqual, recursiveFind, recursiveMap, sleepFunc} from "jh-utils";
import styles from './index.module.less'
import debounce from "lodash-es/debounce";
import {updateTreeData, indexOfKeys} from './helper'

const {Search} = Input;
/**
 * 树组件基类
 * （1）数据源：state.list，以 props.compData 为初始值。
 * （2）操作：搜索节点；
 */
export default class TreeBase extends BaseComp {

    static propTypes = {
        ...BaseComp.propTypes,
        compData: PropTypes.arrayOf(PropTypes.object),
        isSearch: PropTypes.bool,
        searchStyle: PropTypes.object,
        onSearch: PropTypes.func,
        onSelect: PropTypes.func,
        afterSelect: PropTypes.func,
        onExpand: PropTypes.func,
        afterExpand: PropTypes.func,
    };

    static defaultProps = {
        isSearch: true
    };

    // 返回一个对象来更新 state
    static getDerivedStateFromProps(nextProps, preState) {

        if (!isObjectValEqual(nextProps, {compData: preState.propList}, ['compData'])) {
            return {
                list: cloneDeep(nextProps.compData),
                propList: nextProps.compData,
            }
        }
        return null;
    }

    contextMenuId = getRandomKey();

    /**
     * 标识当前是否正在点击操作按钮。
     * 比如：点击节点右侧的“删除”按钮，则不执行节点选中逻辑
     * @type {boolean}
     */
    clickingAct = false;

    constructor(props) {
        super(props);

        this.hdlChangeSearch = debounce(this.hdlChangeSearch.bind(this), 300);
    }

    initState(props) {
        return {
            ...super.initState(props),
            searchValue: '',
            list: cloneDeep(props.compData),
            propList: props.compData,
            originList: props.compData,
            selectedKeys: [],
            // loadedKeys: [],
            expandedKeys: [],
            autoExpandParent: false
        }
    }

    /**
     * 获取组件的数据
     * @return {*}
     */
    getAjaxData() {
        return this.state.list;
    }

    getData() {
        return this.getAjaxData();
    }

    /**
     * 设置数据
     * @param treeData {[{key: string, title: string, name: string, children?:[object]}]}
     * @param afterCb {function | null}
     * @param updateOrigin {boolean} 是否需要更新 state.originList
     */
    setData(treeData, afterCb = null, updateOrigin = true) {
        const newState = {
            list: cloneDeep(treeData)
        };

        if(updateOrigin) {
            newState.originList = treeData;
        }
        this.setState(newState, afterCb);
    }

    resetData(treeData, afterCb) {
        this.setState({
            list: cloneDeep(treeData),
            originList: treeData,
            selectedKeys: [],
            // loadedKeys: [],
            expandedKeys: [],
            autoExpandParent: false
        }, afterCb);
    }

    /**
     * 根据 key 更新树的 children 数据
     * @param key
     * @param children
     * @param afterCb
     */
    updateDataByKey(key, children, afterCb) {
        const newList = updateTreeData(this.state.list, key, children);
        this.setState({list: newList}, afterCb);
    }

    getNodeByKey(key) {
        return recursiveFind(this.state.list, (item) => (item && item.key === key));
    }

    updateNodeByKey(key, nodeData, afterCb) {
        recursiveFind(this.state.list, (item, ind, pItem) => {
            if (item && item.key === key) {
                forIn(nodeData, (v, k) => {
                    item[k] = v;
                });
                return true;
            }
            return false;
        });

        this.setState({randomKey: getRandomKey()}, afterCb);
    }

    isExistByKey(key) {
        return !isEmpty(this.getNodeByKey(key));
    }

    /**
     * 根据 keys 展开节点
     * @param keys {[string]}
     * @param afterCb
     */
    expandNodeByKeys(keys, afterCb) {
        if (!isEmpty(keys) && isArray(keys)) {
            const moreKeys = [...(this.state.expandedKeys || [])];
            forEach(keys, (key) => {
                if (-1 === findIndex(this.state.expandedKeys, (k) => (k === key))) {
                    moreKeys.push(key)
                }
            });
            this.setState({expandedKeys: moreKeys}, afterCb);

        } else {
            afterCb && afterCb();
        }
    }

    /**
     * 点击展开/收缩的回调
     * @param expandedKeys {string[]}
     * @param moreData {{expanded: boolean, node, nativeEvent: MouseEvent}}
     */
    hdlExpand(expandedKeys, moreData) {

        setTimeout(() => {
            let newExpandedKeys = this.runPropsFunc('onExpand')(expandedKeys, moreData);

            if (newExpandedKeys === false) return false;

            this.setState({
                expandedKeys: isArray(newExpandedKeys) ? newExpandedKeys : expandedKeys,
                autoExpandParent: false,
            }, () => {

                this.runPropsFunc('afterExpand')(this.state.expandedKeys, moreData);
            });
        }, 0);
    }

    /**
     * 选择节点之后的回调
     * @param keys {string[]} 选中的节点
     * @param event {{selected: boolean, selectedNodes, node, event}}
     */
    hdlSelect(keys, event) {
        const { isUnChecked } = this.getProps();
        const selNode = event.node;
        let checkInd = indexOf(this.state.selectedKeys, selNode.key);
        let newSelKeys = [selNode.key];
        if(isUnChecked === true && checkInd > -1){
            newSelKeys = [];
            this.runPropsFunc('onSelect')(newSelKeys, event);
        }else {
            if (-1 < checkInd) {
                return false;
            }
        }

        if (this.clickingAct) {
            this.clickingAct = false;
            return false;
        }


        let newKeys = this.runPropsFunc('onSelect')(newSelKeys, event);

        if (newKeys === false) return false;
        // console.log('select', event.node)

        // if (this.props.multiple) {
        //     newSelKeys = keys;
        // } else {
        //     newSelKeys = [selNode.key]
        // }

        this.setState({
            selectedKeys: isArray(newKeys) ? newKeys : newSelKeys
        }, () => {
            this.runPropsFunc('afterSelect')(this.state.selectedKeys, event);
        });
    }

    /**
     * 搜索框输入后，再执行筛选逻辑之前，会执行此回调。
     * @param value {string} 搜索框的值
     * @return {boolean} 返回 false 时，不再执行默认筛选逻辑。返回 true 时，执行默认的筛选逻辑。
     */
    beforeSearch(value) {
        return true;
    }

    /**
     * 过滤树节点。（仅对非异步请求的情况有效，即不传 props.fetchTree 时）
     * 返回 true 表示 node 出现在筛选结果中。
     * @param node
     * @param searchValue
     * @return {boolean}
     */
    filterTreeNode(node, searchValue) {
        return indexOfKeys(node, ['key', 'code', 'name', 'title'], searchValue)
    }

    hdlSearch(value) {
        // console.log('value', value);

        let goOn = this.beforeSearch(value);

        let onSearch = this.getPropsByName('onSearch');
        if (isFunction(onSearch)) {
            goOn = false !== onSearch({search: value});
        }

        if (goOn) {
            const {list} = this.state;
            const expandedKeys = [];

            if (!isEmpty(value)) {
                recursiveMap(list, (item, ind, parentItem) => {
                    if (parentItem && parentItem.key && this.filterTreeNode(item, value)) {
                        expandedKeys.push(parentItem.key);
                    }
                    return item;
                });
            }

            this.setState({
                expandedKeys,
                searchValue: value,
                autoExpandParent: true,
            });
        }
    }

    hdlChangeSearch(e) {
        const {value} = e.target;
        this.hdlSearch(value);
    };

    // onCheck = (checkedKeys, event) => {
    //     // console.log('onCheck', checkedKeys);
    //     this.setState({checkedKeys});
    //     if (this.props.onCheck) {
    //         this.props.onCheck(checkedKeys, event)
    //     }
    // };

    /**
     * 设置 Tree 组件的属性，每次 render 都会执行此方法
     * @return {{}} 可设置的属性，参照 antd 的 Tree 组件
     */
    setTreePropsInRender() {
        return {}
    }


    renderTree(treeProps, context) {

        return (
            <Tree
                virtual={false}
                {...treeProps}
            />
        )
    }

    mainRender(context) {
        const {list, autoExpandParent, compMoreProps} = this.state;

        const {style, searchStyle, isSearch, compData, border, ...restProps} = this.getProps();
        const moreTreeProps = this.setTreePropsInRender() || {};
        const restTreeProps = {
            ...omit(restProps, keys(moreTreeProps)),
            ...(compMoreProps || {}),
            autoExpandParent,
            blockNode: true,
            expandedKeys: this.state.expandedKeys,
            selectedKeys: this.state.selectedKeys,
            onExpand: this.hdlExpand.bind(this),
            onSelect: this.hdlSelect.bind(this),
            treeData: list,
            ...moreTreeProps
        };

        return (
            <div style={style} className={`${styles.contain} treeBase`}>
                {
                    isSearch ? <div className={styles.top}>
                        <Search style={searchStyle}
                                loading={this.props.loading}
                                onSearch={this.hdlSearch.bind(this)}
                                onKeyDown={(e) => {
                                    e.stopPropagation();
                                }}
                                onChange={(e) => {
                                    e.persist();
                                    this.hdlChangeSearch(e);
                                }}
                        />
                    </div> : null
                }
                <div
                    className={`${styles.tree}`}
                    style={border ? {border: '1px solid #d9d9d9'} : {}}>

                    {this.renderTree(restTreeProps, context)}
                </div>
            </div>
        );
    }

}